'''
Created on 07.05.2012

@author: myaut
'''

from salsa.ast import ASTNode

from PIL import ImageDraw, Image, ImageFont, ImageColor

# ASTVisualNode uses greedy calculations for initial canvas size
DEFAULT_HEIGHT = 20
DEFAULT_WIDTH = 32
DEFAULT_CHAR_WIDTH = 16

def _color(h):
    return ((h >> 16 & 0xFF), (h >> 8 & 0xFF), h & 0xFF)

class ASTColor:
    default = _color(0xDDDDDDD)
    bad = _color(0xFF00000)
    colors = [_color(0xCC9933), _color(0x339966), _color(0x0099FF), _color(0x9999FF), _color(0x33FFCC)]
    
    def __init__(self, cid):
        if cid == 0:
            self.color = self.default
        elif cid >= 0xFFFE:
            self.color = self.bad
        else:
            self.color = self.colors[(cid - 1) % len(self.colors)]
    
    def get(self):
        return self.color

class ASTVisualNodeMixin:
    def get_height(self):
        if self.height == 0:
            self.height = DEFAULT_HEIGHT * (len(self.attrs) + 1)
            
            if self.children:
                self.height += sum(c.get_height() for c in self.children.values())
        
        return self.height
    
    def set_color(self, colorid):
        self.color = ASTColor(colorid)
    
    def get_depth(self):
        if self.width == 0:
            max_attr = [len(aname) + len(avalue) + 4 for (aname, avalue) in self.attrs.items()]
            max_text = max([len(self.name)] + max_attr)            
            self.width = DEFAULT_WIDTH + DEFAULT_CHAR_WIDTH * max_text
        
        cdepth = 0
        if self.children:
            cdepth = max(c.get_depth() for c in self.children.values())
        
        return self.width + cdepth

    def draw(self, idraw, x = 0, y = 0, font=None):
        # print 'Drawing %s @ %d:%d' % (str(self), x, y)
        
        if 'color' not in dir(self):
            self.set_color(0)
        
        text = [self.name]
        
        for (aname, avalue) in self.attrs.items():
            atext = '%s => %s' % (aname, avalue)
            text.append(atext)
        
        # Padding
        vert_pad = 4
        hor_pad = 4
        
        # Line width
        tree_width = DEFAULT_WIDTH
        
        # TextBox width/height
        tbox_width = 0
        tbox_height = hor_pad
        text_line_height = 0
        
        for line in text:
            sz = idraw.textsize(line, font=font)
            
            tbox_width = max(tbox_width, sz[0])
            text_line_height = max(text_line_height, sz[1])
            tbox_height += sz[1]
        
        child_line_width = 0
        for cname in self.children:
            sz = idraw.textsize(cname, font=font)
            
            child_line_width = max(child_line_width, sz[0])
        
        tbox_width += 2 * hor_pad
        child_line_width += 2 * hor_pad
        
        #           +---
        # - TEXT ---|
        #           +---
        #   xt xs  xm  x
        
        tbox_x1 = x 
        tbox_x2 = tbox_x1 + tbox_width + 2 * hor_pad
        
        text_x1 = tbox_x1 + hor_pad
        
        middle_line_x = tbox_x2 + tree_width / 2
        child_line_x2 = middle_line_x + child_line_width
        
        width = child_line_x2 - x
        x += width
        
        orig_y = y
        y += vert_pad
        
        child_y0 = None
        child_y1 = None
        
        fill = (0, 0, 0)
        
        full_child_depth = 0
        
        for (cname, child) in self.children.items():            
            (cd, ch) = child.draw(idraw, x, y, font=font)
            
            # Draw line to child
            child_line_y = y + ch/2
            
            if child_y0 is None:
                child_y0 = child_line_y
            child_y1 = child_line_y
            
            full_child_depth = max(full_child_depth, cd)
            
            idraw.text((middle_line_x, child_line_y), cname, fill=fill, font=font)
            idraw.line([(middle_line_x, child_line_y), (child_line_x2, child_line_y)], fill=fill)
            
            y += ch + vert_pad
        
        # Line for all children
        if child_y0 != child_y1:
            idraw.line([(middle_line_x, child_y0), (middle_line_x, child_y1)], fill=fill)
        
        height = max((y - orig_y), tbox_height)
        
        this_line_y = orig_y + height / 2
        text_y = this_line_y - tbox_height / 2
        
        # Text Box   
        tbox_line = [(tbox_x1, text_y), (tbox_x2, text_y), (tbox_x2, text_y + tbox_height), (tbox_x1, text_y + height)]
        idraw.rectangle([(tbox_x1, text_y), (tbox_x2, text_y + tbox_height)], fill=self.color.get())
        
        for i in range(3):
            idraw.line(tbox_line[i:i+1], fill=fill)
        
        # 
        idraw.line([(tbox_x2, this_line_y), (middle_line_x, this_line_y)], fill=fill)
        
        for line in text:
            idraw.text((text_x1, text_y), line , fill=fill, font=font)
            text_y += text_line_height
        
        return (width + full_child_depth, height)
    
    def draw_dendrogram(self, name, fontname = None):
        if fontname:
            font = ImageFont.truetype(fontname, 12)
        
        height = self.get_height()
        width = self.get_depth()
        
        img = Image.new('RGB', (width, height), (255, 255, 255))
        idraw = ImageDraw.Draw(img)
        
        (w, h) = self.draw(idraw, font=font)
        
        img = img.crop((0, 0, w, h))
        
        img.save(name, 'png')